﻿using System;
using System.Collections.Generic;

namespace GeneticAlgorithm.Interfaces
{
    /// <summary>
    /// 停止进化条件
    /// </summary>
    public enum StopCondition
    {
        /// <summary>
        /// 到达迭代次数
        /// </summary>
        ReachIterationNumber = 0,
        /// <summary>
        /// 到达预设条件
        /// </summary>
        ReachPresupposedCondition = 1
    }

    /// <summary>
    /// 定义了一组用于实现遗传算法的属性与方法
    /// </summary>
    /// <typeparam name="T">基因所携带遗传信息的类型</typeparam>
    public interface IGeneticAlgorithm<T>
    {
        /// <summary>
        /// 种群
        /// </summary>
        List<IEvolvable<T>> Population { get; set; }

        /// <summary>
        /// 该遗传算法的终止条件
        /// </summary>
        StopCondition Condition { get; set; }

        /// <summary>
        /// 当前迭代次数
        /// </summary>
        int CurrentIterationNumber { get; set; }

        /// <summary>
        /// 迭代次数。仅在停止进化条件为ReachIterationNumber时生效
        /// </summary>
        int IterationNumber { get; set; }

        /// <summary>
        /// 获取种群中最优秀的个体
        /// </summary>
        IEvolvable<T> BestIndividual { get; }

        /// <summary>
        /// 检查种群是否已进化到满足预设的条件。仅在停止进化条件为ReachPresupposedCondition时生效
        /// </summary>
        /// <returns></returns>
        bool ReachPresupposedCondition();

        /// <summary>
        /// 筛选优胜的个体进行繁殖
        /// </summary>
        /// <param name="originalPopulation">参与筛选的个体集合</param>
        /// <returns>通过筛选的个体集合</returns>
        List<IEvolvable<T>> ScreenParents(List<IEvolvable<T>> originalPopulation);

        /// <summary>
        /// 筛选下一代个体
        /// </summary>
        /// <param name="originalPopulation">当前代种群</param>
        /// <returns>通过筛选的个体</returns>
        List<IEvolvable<T>> ScreenIndividuals(List<IEvolvable<T>> originalPopulation);

        /// <summary>
        /// 繁殖下一代
        /// </summary>
        /// <param name="parents">用于繁殖的个体集合</param>
        /// <returns>繁殖得到的后代</returns>
        List<IEvolvable<T>> Reproduce(List<IEvolvable<T>> parents);

        /// <summary>
        /// 判断是否继续执行遗传算法
        /// </summary>
        /// <returns></returns>
        bool CanContinue
        {
            get
            {
                if (Condition == StopCondition.ReachIterationNumber)
                    return CurrentIterationNumber < IterationNumber;
                else
                    return !ReachPresupposedCondition();
            }
        }

        /// <summary>
        /// 执行遗传算法
        /// </summary>
        void Execute(List<IEvolvable<T>> initialPopulation)
        {
            if (initialPopulation == null)
                throw new NullReferenceException("初始种群不能为null");
            else
                Population = initialPopulation;
            while (CanContinue)
            {
                Population.AddRange(Reproduce(ScreenParents(Population)));
                Population = ScreenIndividuals(Population);
                CurrentIterationNumber += 1;
            }
        }
    }
}
